package com.cvte.sunkit.ui.window

import android.annotation.SuppressLint
import android.content.res.Resources
import android.graphics.Color
import android.view.*
import android.view.WindowManager.LayoutParams
import com.cvte.sunkit.App
import com.cvte.sunkit.R
import com.cvte.sunkit.callback.ChartFloatListener
import com.cvte.sunkit.model.PerfData
import com.cvte.sunkit.ui.base.BaseWindow
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet

/**
 *  @PackageName com.cvte.sunkit.ui.window
 *  @Description 折线浮窗
 *  @Author lixu
 *  @Data 2023/7/24 09:56
 *  @Version 1.0
 */
class ChartFloatWindow(private val windowManager: WindowManager) : BaseWindow(),ChartFloatListener {

    private lateinit var mLayoutParams: LayoutParams
    private var mFloatWindow: View? = null

    private var mCpuChart: LineChart? = null
    private var mLineDataSet = LineDataSet(null, "CPU占用") // 一个LineDataSet就是一条线
    private var mLineData = LineData()

    private var mMemChart: LineChart? = null
    private var mMemLineDataSet = LineDataSet(null, "可用内存")
    private var mMemLineData = LineData()

    private var mIoChart: LineChart? = null
    private var mIoInLineDataSet = LineDataSet(null, "读取速率")
    private var mIoOutLineDataSet = LineDataSet(null, "写回速率")
    private var mIoLineData: LineData = LineData()


    companion object {
        var isWindowOpened = false
        var isShowMemView = false
        var isShowCpuView = false
        var isShowIoView = false
    }

    @SuppressLint("InflateParams")
    override fun addView() {
        if (!isWindowOpened) {
            mFloatWindow = LayoutInflater.from(App.mInstance.applicationContext)
                .inflate(R.layout.float_data_chart, null)
            showWindow()
            mLayoutParams = initLayoutParams()

            windowManager.addView(mFloatWindow, mLayoutParams)
            isWindowOpened = true
        }
    }

    override fun removeView() {
        hideCpuView()
        hideMemView()
        hideIoView()


        if (isWindowOpened) {
            windowManager.removeView(mFloatWindow)
            mIoChart = null
            mCpuChart = null
            mMemChart = null
            mFloatWindow = null
        }
        isWindowOpened = false
    }

    override fun showMemView() {
        if (!isShowMemView) {
            mMemChart?.visibility = View.VISIBLE
            isShowMemView = true
        }
    }

    override fun hideMemView() {
        if (isShowMemView) {
            mMemLineDataSet.clear()
            mMemLineData.clearValues()
            mMemChart?.data?.clearValues()
            mMemChart?.invalidate()
            mMemChart?.visibility = View.GONE
            mMemChart?.clear()
            isShowMemView = false
        }
    }

    override fun showCpuView() {
        if (!isShowCpuView) {
            mCpuChart?.visibility = View.VISIBLE
            isShowCpuView = true
        }
    }

    override fun hideCpuView() {
        if (isShowCpuView) {
            mLineDataSet.clear()
            mLineData.clearValues()
            mCpuChart?.data?.clearValues()
            mCpuChart?.invalidate()
            mCpuChart?.visibility = View.GONE
            mCpuChart?.clear()
            isShowCpuView = false
        }
    }

    override fun showIoView() {
        if (!isShowIoView) {
            mIoChart?.visibility = View.VISIBLE
            isShowIoView = true
        }
    }

    override fun hideIoView() {
        if (isShowIoView) {
            mIoInLineDataSet.clear()
            mIoOutLineDataSet.clear()
            mIoLineData.clearValues()
            mIoChart?.data?.clearValues()
            mIoChart?.invalidate()
            mIoChart?.visibility = View.GONE
            mIoChart?.clear()
            isShowIoView = false
        }
    }

    override fun updateUI(data: PerfData, resources: Resources) {
        if (isShowCpuView) {
            addCpuEntry(data.sysCpuUsage.toFloat())
        }
        if (isShowMemView) {
            addMemEntry(data.memAvail.toFloat())
        }
        if (isShowIoView) {
            addIoEntry(data.inSpeed.toFloat(), data.outSpeed.toFloat())
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    private fun showWindow() {
        mCpuChart = mFloatWindow?.findViewById(R.id.cpu_chart)
        mMemChart = mFloatWindow?.findViewById(R.id.mem_chart)
        mIoChart = mFloatWindow?.findViewById(R.id.io_chart)

        initLineChart()

        mFloatWindow?.setOnTouchListener(FloatingOnTouchListener(windowManager))
    }

    private fun initLineChart() { // 初始化折线图样式
        mCpuChart?.let {
            it.setNoDataText("暂无数据")
            it.axisRight?.isEnabled = false
            it.xAxis?.position = XAxis.XAxisPosition.BOTTOM
            it.invalidate()
        }
        mMemChart?.let {
            it.setNoDataText("暂无数据")
            it.axisRight?.isEnabled = false
            it.xAxis?.position = XAxis.XAxisPosition.BOTTOM
            it.invalidate()
        }
        mIoChart?.let {
            it.setNoDataText("暂无数据")
            it.axisRight?.isEnabled = false
            it.xAxis?.position = XAxis.XAxisPosition.BOTTOM
            it.invalidate()
        }
    }

    private fun addCpuEntry(number: Float) { // 动态添加数据
        if (mLineDataSet.entryCount == 0) {
            mLineData.addDataSet(mLineDataSet)
        }

        mCpuChart?.data = mLineData
        val entry = Entry(mLineDataSet.entryCount.toFloat(), number)
        mLineData.addEntry(entry, 0)
        mLineData.notifyDataChanged()
        mCpuChart?.notifyDataSetChanged()
        mCpuChart?.setVisibleXRangeMaximum(20F)

        mCpuChart?.moveViewToX(mLineData.entryCount.toFloat() - 5)
    }

    private fun addMemEntry(number: Float) {
        if (mMemLineDataSet.entryCount == 0) {
            mMemLineData.addDataSet(mMemLineDataSet)
        }

        mMemChart?.data = mMemLineData
        val entry = Entry(mMemLineDataSet.entryCount.toFloat(), number)
        mMemLineData.addEntry(entry, 0)
        mMemLineData.notifyDataChanged()
        mMemChart?.notifyDataSetChanged()
        mMemChart?.setVisibleXRangeMaximum(20F)

        mMemChart?.moveViewToX(mMemLineData.entryCount.toFloat() - 5)
    }


    private fun addIoEntry(inSpeed: Float, outSpeed: Float) {
        if (mIoOutLineDataSet.entryCount == 0) {
            mIoInLineDataSet.color = Color.RED
            mIoInLineDataSet.valueTextColor = Color.RED
            mIoLineData.addDataSet(mIoOutLineDataSet)
        }
        if (mIoInLineDataSet.entryCount == 0) {
            mIoLineData.addDataSet(mIoInLineDataSet)
        }
        val index =
            if (mIoInLineDataSet.entryCount > mIoOutLineDataSet.entryCount) mIoInLineDataSet.entryCount else mIoOutLineDataSet.entryCount
        val inEntry = Entry(index.toFloat(), inSpeed)
        val outEntry = Entry(index.toFloat(), outSpeed)
        mIoInLineDataSet.addEntry(inEntry)
        mIoOutLineDataSet.addEntry(outEntry)

        mIoChart?.data = mIoLineData
        mIoLineData.notifyDataChanged()
        mIoChart?.let {
            it.notifyDataSetChanged()
            it.setVisibleXRangeMaximum(20F)
            it.moveViewToX(index.toFloat() - 5)
            it.invalidate()
        }
    }
}